﻿using System;
using System.Configuration;
using System.Drawing;
using System.IO;
using System.ServiceModel.DomainServices.Server;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate.Tool.hbm2ddl;
using log4net;

namespace MVVMtutorialAdvanced.Web
{
	public class Global : System.Web.HttpApplication
	{
		public static ILog _log;
		public static NHibernate.ISessionFactory SessionFactory;

		protected void Application_Start(object sender, EventArgs e)
		{
			log4net.Config.XmlConfigurator.Configure();
			_log = LogManager.GetLogger(typeof(Global));
			_log.Debug("----------------- Application_Start");

			#region alternative config
			//var configuration = new NHibernate.Cfg.Configuration();
			//configuration.Configure();

			//configuration.DataBaseIntegration
			//  (
			//    configProperties =>
			//    {
			//      configProperties.Dialect<SQLiteDialect>();
			//      configProperties.Driver<SQLite20Driver>();
			//      //configProperties.ConnectionProvider<TestConnectionProvider>();

			//      configProperties.ConnectionString =
			//        string.Format(@"Data Source={0};Version=3;New=True;", @"D:\DevGranwehr\NHibernate_Playground\src\DB\test.db");

			//      configProperties.LogFormatedSql = true;
			//      configProperties.BatchSize = 100;
			//    }
			//  );

			//configuration.SetProperty(NHibernate.Cfg.Environment.CurrentSessionContextClass, "thread_static");

			//configuration.SetProperty
			//  (
			//    NHibernate.Cfg.Environment.ProxyFactoryFactoryClass,
			//    typeof(NHibernate.ByteCode.LinFu.ProxyFactoryFactory).AssemblyQualifiedName
			//  );

			//configuration.AddAssembly("MVVMtutorialAdvanced.Web");

			//SessionFactory = configuration.BuildSessionFactory();
			#endregion

			SessionFactory = CreateSessionFactory();
			DomainService.Factory = new DomainServiceFactoryRiba();  //Register factory

			var buildSchema = bool.Parse(ConfigurationManager.AppSettings.Get("BuildSchema"));
			if (buildSchema)
				FillDB();

			_log.Debug("----------------- End Application_Start");
		}

		private static string _database;
		private static NHibernate.ISessionFactory CreateSessionFactory()
		{
			_database = System.Web.Configuration.WebConfigurationManager.AppSettings.Get("Database");
			FluentConfiguration configuration = Fluently.Configure();

			if (_database == "SQLServer2008")
			{
				var connectionString = ConfigurationManager.ConnectionStrings["SQLServer2008"].ConnectionString;
				configuration.Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString));
			}
			else if (_database == "SQLServer2005")
			{
				var connectionString = ConfigurationManager.ConnectionStrings["SQLServer2005"].ConnectionString;
				configuration.Database(MsSqlConfiguration.MsSql2005.ConnectionString(connectionString).ShowSql);
			}
			// System.Data.SQLite 1.0.76 : from sqlite-netFx40-static-binary-bundle-Win32-2010-1.0.76.0
			else
				configuration.Database(SQLiteConfiguration.Standard.UsingFile(DbFile).ShowSql);

			configuration
				.ExposeConfiguration(c => c.SetProperty("command_timeout", "120"))
				.ExposeConfiguration
					(
						x => x.SetProperty(
							"proxyfactory.factory_class",
							"NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu")
					)
				.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Author>());

			var buildSchema = bool.Parse(ConfigurationManager.AppSettings.Get("BuildSchema"));
			if (buildSchema)
				configuration.ExposeConfiguration(BuildSchema);

			return configuration.BuildSessionFactory();
		}

		private static void BuildSchema(NHibernate.Cfg.Configuration config)
		{
			_log.Debug("----------------- BuildSchema");

			// delete the existing db on each run
			if (_database == "SQLite")
				if (File.Exists(DbFile))
					File.Delete(DbFile);

			new SchemaExport(config)
				.Create(false, true);
		}

		private static void FillDB()
		{
			using (var session = SessionFactory.OpenSession())
			using (var transaction = session.BeginTransaction())
			{
				//-----------------------------------------------------------------------------------
				var country1 = new Country { Alias = "-", IsoCode = "-" };
				session.Save(country1);
				var country2 = new Country { Alias = "Schweiz", IsoCode = "CH" };
				session.Save(country2);
				var country3 = new Country { Alias = "Deutschland", IsoCode = "DE" };
				session.Save(country3);
				var country4 = new Country { Alias = "Italien", IsoCode = "IT" };
				session.Save(country4);
				var country5 = new Country { Alias = "Frankreich", IsoCode = "FR" };
				session.Save(country5);
				var country6 = new Country { Alias = "USA", IsoCode = "US" };
				session.Save(country6);

				//-----------------------------------------------------------------------------------
				var author1 = new Author {FirstName = "Michael C", LastName = "Feathers"};
				session.Save(author1);
				var author2 = new Author {FirstName = "Martin", LastName = "Fowler"};
				session.Save(author2);
				var author3 = new Author {FirstName = "Erich", LastName = "Gamma"};
				session.Save(author3);
				var author4 = new Author {FirstName = "Richard", LastName = "Helm"};
				session.Save(author4);
				var author5 = new Author {FirstName = "Ralph", LastName = "Johnson"};
				session.Save(author5);
				var author6 = new Author {FirstName = "John M", LastName = "Vlissides"};
				session.Save(author6);
				var author7 = new Author { FirstName = "Gabriel", LastName = "Schenker" };
				session.Save(author7);

				//-----------------------------------------------------------------------------------

				// Book 1 -----------------------
				var fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\cover1.jpg");
				var cover1 = Image.FromFile(fileName);

				var book1 = new Book
				  {
				    Title = "Working Effectively with Legacy Code",
						Price = 45.2M,
						IsOutOfStock = false,
						Release = new DateTime(2004, 10, 2),
						Country = country5,
						Cover = ImageToByteArray(cover1)
				  };
				session.SaveOrUpdate(book1);

				book1.AddAuthor(author1);

				// Book 2 -----------------------
				fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\cover2.jpg");
				var cover2 = Image.FromFile(fileName);
				var book2 = new Book
				  {
				    Title = "Patterns of Enterprise Application Architecture",
						Price = 43.25M,
						IsOutOfStock = true,
						Country = country1,
						Cover = ImageToByteArray(cover2)
				  };
				session.SaveOrUpdate(book2);

				book2.AddAuthor(author2);

				// Book 3 -----------------------
				fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\cover3.jpg");
				var cover3 = Image.FromFile(fileName);
				var book3 = new Book
				  {
				    Title = "Design Patterns: Elements of Reusable Object-Oriented Software", 
						Price = 37.75M,
						IsOutOfStock = true,
						Country = country5,
						Cover = ImageToByteArray(cover3)
				  };
				session.SaveOrUpdate(book3);

				book3.AddAuthor(author3);
				book3.AddAuthor(author4);
				book3.AddAuthor(author5);

				// Book 4 -----------------------
				fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\cover4.jpg");
				var cover4 = Image.FromFile(fileName);
				var book4 = new Book
				{
					Title = "NHibernate 3 Beginners Guide",
					Price = 40.0M,
					IsOutOfStock = true,
					Country = country2,
					Cover = ImageToByteArray(cover4)
				};
				session.SaveOrUpdate(book4);

				book4.AddAuthor(author7);

				transaction.Commit();
			}
		}

		private static byte[] ImageToByteArray(Image imageIn)
		{
			try
			{
				var ms = new MemoryStream();
				imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
				return ms.ToArray();
			}
			catch (Exception ex)
			{
				_log.Error(ex);
				throw;
			}
		}

		private static readonly string DbFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"App_Data\_data.db");

		protected void Session_Start(object sender, EventArgs e) { }

		protected void Application_BeginRequest(object sender, EventArgs e) { }

		protected void Application_AuthenticateRequest(object sender, EventArgs e) { }

		protected void Application_Error(object sender, EventArgs e)
		{
			Exception ex = Context.Server.GetLastError();

			_log.Error("------------ Application_Error", ex);

			//if (ex.InnerException != null)
			//{
			//  _log.Error("------------ Application_Error.InnerException", ex.InnerException);
			//  if (ex.InnerException.InnerException != null)
			//    _log.Error("------------ Application_Error.InnerException.InnerException", ex.InnerException.InnerException);
			//}
		}

		protected void Session_End(object sender, EventArgs e) { }

		protected void Application_End(object sender, EventArgs e) { }
	}
}